#include "StdAfx.h"
#include "alltabs.h"
#include ".\httpget.h"

#define MAX_READ 5 // this is the speed of the download. UI is blocked during dl


CHttpGet::CHttpGet(CAllTabs *allTabs, int mode, CPrefTab *prefs) : _isStarted(false), _requested(false)
, _prefs(prefs)
{
	session = NULL;
	httpConnection = NULL;
	_allTabs = allTabs;
	_mode = mode;
}

CHttpGet::CHttpGet(void)
: _isStarted(false)
, _requested(false)
, _mode(0)
, _stop(0)
, _prefs(NULL)
{
	session = NULL;
	httpConnection = NULL;
}

CHttpGet::~CHttpGet(void)
{
	int i;

	// cleaning
	POSITION pos = _xmlList.GetHeadPosition();
	for (i = 0; i < _xmlList.GetCount(); i++)
	{
		delete _xmlList.GetNext(pos);
	}
	pos = _fileXmlList.GetHeadPosition();
	for (i = 0; i < _fileXmlList.GetCount(); i++)
	{
		delete _fileXmlList.GetNext(pos);
	}

	if (httpConnection) {
		httpConnection->Close();
		delete httpConnection;
	}
	if (session) {
		session->Close();
		delete session;
	}
}

bool CHttpGet::downloadFile(LPCTSTR pszURL, LPCTSTR fileName) {
	if (_isStarted)
		return addRequest(pszURL, fileName);
	_isStarted = true;

	if (_prefs->_proxyData == FALSE)
		session = new CInternetSession("mTs");
	else
		session = new CInternetSession("mTs"
		,1,INTERNET_OPEN_TYPE_PROXY, _prefs->_proxyServerData, 0, 0);
	try{

		CString strServerName;
		CString strObject;
		INTERNET_PORT nPort;
		DWORD dwServiceType;

		if (!AfxParseURL(pszURL, dwServiceType, strServerName, strObject, nPort) ||
			dwServiceType != INTERNET_SERVICE_HTTP)
		{
			return false;
			AfxMessageBox("Parse URL error\n", NULL, NULL);
		}
		session->SetOption(INTERNET_OPTION_CONNECT_RETRIES, 1);
        session->SetOption(INTERNET_OPTION_SEND_TIMEOUT, 5000);
        session->SetOption(INTERNET_OPTION_RECEIVE_TIMEOUT, 5000);
		session->SetOption(INTERNET_OPTION_CONNECT_TIMEOUT, 5000);
		httpConnection = session->GetHttpConnection(strServerName, nPort);
		if (addRequest(pszURL, fileName))
			return true;
	}
	catch (CInternetException* pEx)
	{
		// catch errors from WinINet
		TCHAR szErr[1024];
		pEx->GetErrorMessage(szErr, 1024);
		pEx->Delete();
	}
	return false;
}
bool CHttpGet::addRequest(LPCTSTR pszURL, LPCTSTR fileName) {
	const TCHAR szHeaders[] = _T("Accept: */*\r\nUser-Agent: mTs\r\n");

	CString strServerName;
	CString strObject;
	INTERNET_PORT nPort;
	DWORD dwServiceType;

	if (!AfxParseURL(pszURL, dwServiceType, strServerName, strObject, nPort) ||
		dwServiceType != INTERNET_SERVICE_HTTP)
	{
		return false;
		AfxMessageBox("Parse URL error\n", NULL, NULL);
	}
	if (_mode == 1)
		_xmlList.AddHead(httpConnection->OpenRequest(CHttpConnection::HTTP_VERB_POST,
		strObject, NULL, 1, NULL, NULL, INTERNET_FLAG_DONT_CACHE));
	else
		_xmlList.AddHead(httpConnection->OpenRequest(CHttpConnection::HTTP_VERB_GET,
		strObject, NULL, 1, NULL, NULL, INTERNET_FLAG_DONT_CACHE));
	(_xmlList.GetHead())->AddRequestHeaders(szHeaders);

	// Lets write the file locally
	_fileXmlList.AddHead(new CFile());
	if ((_fileXmlList.GetHead())->Open(fileName, CFile::modeCreate | CFile::modeWrite))
		return true;
	cutHead();
	return false;
}

void CHttpGet::Download(void)
{
	if (_stop == FALSE)
		AfxBeginThread(MyThreadProc, this);
	else 
		killThread();
	return;
}

CString CHttpGet::getFileName(void)
{
	if (!_fileXmlList.IsEmpty())
		return (_fileXmlList.GetHead())->GetFilePath();
	return "";
}


bool CHttpGet::isEmpty(void)
{
	if (_xmlList.IsEmpty()) {
		return true;
	}
	return false;
}

bool CHttpGet::cutHead(void)
{
	if (_fileXmlList.IsEmpty() || _xmlList.IsEmpty())
		return false;

	_requested = false;

	// Prepare for the next file
	(_fileXmlList.GetHead())->Abort();
	delete (_fileXmlList.GetHead());
	_fileXmlList.RemoveHead();

	(_xmlList.GetHead())->Close();
	delete (_xmlList.GetHead());
	_xmlList.RemoveHead();
	return true;
}

#define DOWNLOAD_BUFFER 256
UINT MyThreadProc( LPVOID pParam ) {
    CHttpGet* httpGet = (CHttpGet*)pParam;

    if (httpGet == NULL || httpGet->_xmlList.IsEmpty()) // second test is bad!
		return 1;   // if pObject is not valid

    // do something with 'pObject'
	try {
		if (!httpGet->_requested && httpGet->_stop == FALSE) {
			httpGet->_requested = true;
			if (!httpGet->_xmlList.IsEmpty())
				(httpGet->_xmlList.GetHead())->SendRequest();
			else
				return 0;
			DWORD dwRet;
			if (!httpGet->_xmlList.IsEmpty())
				(httpGet->_xmlList.GetHead())->QueryInfoStatusCode(dwRet);
			else
				return 0;
			if (dwRet == HTTP_STATUS_DENIED) {
				AfxMessageBox("access denied\n", NULL, NULL);
				return 0;
			}
		}
		// Read the file
		TCHAR sz[DOWNLOAD_BUFFER];
		int read = 1;
		while(read && httpGet->_stop == FALSE)
		{
			if ((read = (httpGet->_xmlList.GetHead())->Read(sz, DOWNLOAD_BUFFER))) {
				(httpGet->_fileXmlList.GetHead())->Write(sz, read);
			}
		}
		// Classic mode
		if (httpGet->_mode < 2 && httpGet->_stop == FALSE)
			httpGet->_allTabs->checkDownload();
		// mode 2 is for check version. It turns into mode 3 when version is checked
		else if (httpGet->_mode == 2 && httpGet->_stop == FALSE)
			httpGet->_allTabs->checkVersion();
		// mode 3 is kind of a ping mode. We don't care about the return. Used by miscGrabber
		else if (httpGet->_mode == 3 && httpGet->_stop == FALSE)
			httpGet->cutHead();
	}
	catch (CInternetException* pEx)
	{
		// catch errors from WinINet
		TCHAR szErr[1024];
		pEx->GetErrorMessage(szErr, 1024);
		pEx->Delete();
		if (httpGet->_stop == FALSE)
			httpGet->cutHead();
	}
	if (!httpGet->isEmpty() && httpGet->_stop == FALSE)
		httpGet->Download();
    return 0;   // thread completed successfully
}
int CHttpGet::killThread(void) 
{
	// Classic mode
	if (_mode < 2)
		_allTabs->checkDownload();
	// mode 2 is for check version. It turns into mode 3 when version is checked
	else if (_mode == 2)
		_allTabs->checkVersion();
	// mode 3 is kind of a ping mode. We don't care about the return. Used by miscGrabber
	else if (_mode == 3)
		cutHead();
	if (!isEmpty())
		Download();
	return TRUE;
}
